package net.penguinmenac3.math.rings;

import net.penguinmenac3.math.MathObject;

/**
 * Represents a number containing variables.
 * e.g.: (a+2*b)
 * 
 * @author Michael
 */
public class VariableNumber implements MathObject {
	private String value;

	/**
	 * Initialize with a string.
	 * @param value
	 */
	public VariableNumber(String value) {
		if (value == null) {
			throw new NullPointerException();
		}
		if (value.length() == 0) {
			throw new IllegalArgumentException("Value must be longer than 0");
		}
		this.value = normalize(value);
	}
	
	/**
	 * Initialize with a double.
	 * @param value
	 */
	public VariableNumber(double value) {
		this.value = String.valueOf(value);
	}

	public String getValue() {
		return value;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see penguinmenac3.math.MathObject#add(penguinmenac3.math.MathObject)
	 */
	@Override
	public MathObject add(MathObject o) {
		if (isNullElement()) {
			return new VariableNumber(o.getValue());
		}
		if (o.isNullElement()) {
			return new VariableNumber(getValue());
		}
		if (getValue().equals(o.getValue())) {
			return new VariableNumber("2.0*(" + getValue() + ")");
		}
		return new VariableNumber("(" + getValue() + ")+(" + o.getValue() + ")");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * penguinmenac3.math.MathObject#subtract(penguinmenac3.math.MathObject)
	 */
	@Override
	public MathObject subtract(MathObject o) {
		if (isNullElement()) {
			return new VariableNumber("-"+o.getValue());
		}
		if (o.isNullElement()) {
			return new VariableNumber(getValue());
		}
		if (getValue().equals(o.getValue())) {
			return new VariableNumber("0.0");
		}
		return new VariableNumber("(" + getValue() + ")-(" + o.getValue() + ")");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * penguinmenac3.math.MathObject#multiply(penguinmenac3.math.MathObject)
	 */
	@Override
	public MathObject multiply(MathObject o) {
		if (isNullElement() || o.isNullElement()) {
			return new VariableNumber("0.0");
		}
		if (isNeutralElement()) {
			return new VariableNumber(o.getValue());
		}

		if (o.isNeutralElement()) {
			return new VariableNumber(getValue());
		}
		return new VariableNumber("(" + getValue() + ")*(" + o.getValue() + ")");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see penguinmenac3.math.MathObject#divide(penguinmenac3.math.MathObject)
	 */
	@Override
	public MathObject divide(MathObject o) {
		if (o.isNullElement()) {
			throw new IllegalArgumentException("Division by ZERO");
		}
		if (o.isNeutralElement()) {
			return new VariableNumber(getValue());
		}
		if (isNullElement()) {
			return new VariableNumber(getValue());
		}
		if (getValue().equals(o.getValue())) {
			return new VariableNumber("1.0");
		}
		return new VariableNumber("(" + getValue() + ")/(" + o.getValue() + ")");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see penguinmenac3.math.MathObject#isNeutralElement()
	 */
	@Override
	public boolean isNeutralElement() {
		if (value.equals("1.0")) {
			return true;
		}
		return false;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see penguinmenac3.math.MathObject#isNullElement()
	 */
	@Override
	public boolean isNullElement() {
		if (value.equals("0.0")) {
			return true;
		}
		return false;
	}

	private String normalize(String s) {
		s = s.replaceAll(" ", "");
		return s;
	}

	private String simplify(String s) {
		// TODO
		return s;
	}

	@Override
	public VariableNumber clone() {
		return new VariableNumber(value);
	}
	
	@Override
	public MathObject inverse() {
		VariableNumber one = new VariableNumber(1);
		return one.divide(this);
	}
	
	@Override
	public MathObject additiveInverse() {
		return new VariableNumber("-("+value+")");
	}

	@Override
	public String toString() {
		return simplify(value);
	}
}
